import React, { createRef, CSSProperties, forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";
import { generateBothEyes, generateFaceCountourPoints, generateHairLines0, generateHairLines1, generateHairLines2, generateHairLines3, generateMouthShape0, generateMouthShape1, generateMouthShape2, randomFromInterval } from "@/utils/uglyAvatarGenerator";
const hairColors = [
    "rgb(0, 0, 0)", // Black
    "rgb(44, 34, 43)", // Dark Brown
    "rgb(80, 68, 68)", // Medium Brown
    "rgb(167, 133, 106)", // Light Brown
    "rgb(220, 208, 186)", // Blond
    "rgb(233, 236, 239)", // Platinum Blond
    "rgb(165, 42, 42)", // Red
    "rgb(145, 85, 61)", // Auburn
    "rgb(128, 128, 128)", // Grey
    "rgb(185, 55, 55)", // Fire
    "rgb(255, 192, 203)", // Pastel Pink
    "rgb(255, 105, 180)", // Bright Pink
    "rgb(230, 230, 250)", // Lavender
    "rgb(64, 224, 208)", // Turquoise
    "rgb(0, 191, 255)", // Bright Blue
    "rgb(148, 0, 211)", // Deep Purple
    "rgb(50, 205, 50)", // Lime Green
    "rgb(255, 165, 0)", // Vivid Orange
    "rgb(220, 20, 60)", // Crimson Red
    "rgb(192, 192, 192)", // Silver
    "rgb(255, 215, 0)", // Gold
    "rgb(255, 255, 255)", // White
    "rgb(124, 252, 0)", // Lawn Green
    "rgb(127, 255, 0)", // Chartreuse
    "rgb(0, 255, 127)", // Spring Green
    "rgb(72, 209, 204)", // Medium Turquoise
    "rgb(0, 255, 255)", // Cyan
    "rgb(0, 206, 209)", // Dark Turquoise
    "rgb(32, 178, 170)", // Light Sea Green
    "rgb(95, 158, 160)", // Cadet Blue
    "rgb(70, 130, 180)", // Steel Blue
    "rgb(176, 196, 222)", // Light Steel Blue
    "rgb(30, 144, 255)", // Dodger Blue
    "rgb(135, 206, 235)", // Sky Blue
    "rgb(0, 0, 139)", // Dark Blue
    "rgb(138, 43, 226)", // Blue Violet
    "rgb(75, 0, 130)", // Indigo
    "rgb(139, 0, 139)", // Dark Magenta
    "rgb(153, 50, 204)", // Dark Orchid
    "rgb(186, 85, 211)", // Medium Orchid
    "rgb(218, 112, 214)", // Orchid
    "rgb(221, 160, 221)", // Plum
    "rgb(238, 130, 238)", // Violet
    "rgb(255, 0, 255)", // Magenta
    "rgb(216, 191, 216)", // Thistle
    "rgb(255, 20, 147)", // Deep Pink
    "rgb(255, 69, 0)", // Orange Red
    "rgb(255, 140, 0)", // Dark Orange
    "rgb(255, 165, 0)", // Orange
    "rgb(250, 128, 114)", // Salmon
    "rgb(233, 150, 122)", // Dark Salmon
    "rgb(240, 128, 128)", // Light Coral
    "rgb(205, 92, 92)", // Indian Red
    "rgb(255, 99, 71)", // Tomato
    "rgb(255, 160, 122)", // Light Salmon
    "rgb(220, 20, 60)", // Crimson
    "rgb(139, 0, 0)", // Dark Red
    "rgb(178, 34, 34)", // Fire Brick
    "rgb(250, 235, 215)", // Antique White
    "rgb(255, 239, 213)", // Papaya Whip
    "rgb(255, 235, 205)", // Blanched Almond
    "rgb(255, 222, 173)", // Navajo White
    "rgb(245, 245, 220)", // Beige
    "rgb(255, 228, 196)", // Bisque
    "rgb(255, 218, 185)", // Peach Puff
    "rgb(244, 164, 96)", // Sandy Brown
    "rgb(210, 180, 140)", // Tan
    "rgb(222, 184, 135)", // Burly Wood
    "rgb(250, 250, 210)", // Light Goldenrod Yellow
    "rgb(255, 250, 205)", // Lemon Chiffon
    "rgb(255, 245, 238)", // Sea Shell
    "rgb(253, 245, 230)", // Old Lace
    "rgb(255, 228, 225)", // Misty Rose
    "rgb(255, 240, 245)", // Lavender Blush
    "rgb(250, 240, 230)", // Linen
    "rgb(255, 228, 181)", // Moccasin
    "rgb(255, 250, 250)", // Snow
    "rgb(240, 255, 255)", // Azure
    "rgb(240, 255, 240)", // Honeydew
    "rgb(245, 245, 245)", // White Smoke
    "rgb(245, 255, 250)", // Mint Cream
    "rgb(240, 248, 255)", // Alice Blue
    "rgb(240, 248, 255)", // Ghost White
    "rgb(248, 248, 255)", // Ghost White
    "rgb(255, 250, 240)", // Floral White
    "rgb(253, 245, 230)", // Old Lace
]

const backgroundColors = [
    "rgb(245, 245, 220)", // Soft Beige
    "rgb(176, 224, 230)", // Pale Blue
    "rgb(211, 211, 211)", // Light Grey
    "rgb(152, 251, 152)", // Pastel Green
    "rgb(255, 253, 208)", // Cream
    "rgb(230, 230, 250)", // Muted Lavender
    "rgb(188, 143, 143)", // Dusty Rose
    "rgb(135, 206, 235)", // Sky Blue
    "rgb(245, 255, 250)", // Mint Cream
    "rgb(245, 222, 179)", // Wheat
    "rgb(47, 79, 79)", // Dark Slate Gray
    "rgb(72, 61, 139)", // Dark Slate Blue
    "rgb(60, 20, 20)", // Dark Brown
    "rgb(25, 25, 112)", // Midnight Blue
    "rgb(139, 0, 0)", // Dark Red
    "rgb(85, 107, 47)", // Olive Drab
    "rgb(128, 0, 128)", // Purple
    "rgb(0, 100, 0)", // Dark Green
    "rgb(0, 0, 139)", // Dark Blue
    "rgb(105, 105, 105)", // Dim Gray
    "rgb(240, 128, 128)", // Light Coral
    "rgb(255, 160, 122)", // Light Salmon
    "rgb(255, 218, 185)", // Peach Puff
    "rgb(255, 228, 196)", // Bisque
    "rgb(255, 222, 173)", // Navajo White
    "rgb(255, 250, 205)", // Lemon Chiffon
    "rgb(250, 250, 210)", // Light Goldenrod Yellow
    "rgb(255, 239, 213)", // Papaya Whip
    "rgb(255, 245, 238)", // Sea Shell
    "rgb(255, 248, 220)", // Cornsilk
    "rgb(255, 255, 240)", // Ivory
    "rgb(240, 255, 240)", // Honeydew
    "rgb(240, 255, 255)", // Azure
    "rgb(240, 248, 255)", // Alice Blue
    "rgb(248, 248, 255)", // Ghost White
    "rgb(255, 250, 250)", // Snow
    "rgb(255, 240, 245)", // Lavender Blush
    "rgb(255, 228, 225)", // Misty Rose
    "rgb(230, 230, 250)", // Lavender
    "rgb(216, 191, 216)", // Thistle
    "rgb(221, 160, 221)", // Plum
    "rgb(238, 130, 238)", // Violet
    "rgb(218, 112, 214)", // Orchid
    "rgb(186, 85, 211)", // Medium Orchid
    "rgb(147, 112, 219)", // Medium Purple
    "rgb(138, 43, 226)", // Blue Violet
    "rgb(148, 0, 211)", // Dark Violet
    "rgb(153, 50, 204)", // Dark Orchid
    "rgb(139, 69, 19)", // Saddle Brown
    "rgb(160, 82, 45)", // Sienna
    "rgb(210, 105, 30)", // Chocolate
    "rgb(205, 133, 63)", // Peru
    "rgb(244, 164, 96)", // Sandy Brown
    "rgb(222, 184, 135)", // Burly Wood
    "rgb(255, 250, 240)", // Floral White
    "rgb(253, 245, 230)", // Old Lace
    "rgb(250, 240, 230)", // Linen
]
type Props = {
    size?: number,
    src?: string
}

const UglyAvatar = forwardRef<UglyRef, Props>((props, ref) => {
    const [faceScale, setFaceScale] = useState(1.8); //面部比例
    const [computedFacePoints, setComputedFacePoints] = useState<any>(); // 计算的面部点
    const [eyeRightUpper, setEyeRightUpper] = useState<any>();
    const [eyeRightLower, setEyeRightLower] = useState<any>();
    const [eyeRightCountour, setEyeRightCountour] = useState<any>();
    const [eyeLeftUpper, setEyeLeftUpper] = useState();
    const [eyeLeftLower, setEyeLeftLower] = useState();
    const [eyeLeftCountour, setEyeLeftCountour] = useState();
    const [center, setCenter] = useState([0, 0]);
    const [distanceBetweenEyes, setDistanceBetweenEyes] = useState(0);
    const [leftEyeOffsetX, setLeftEyeOffsetX] = useState(0);
    const [leftEyeOffsetY, setLeftEyeOffsetY] = useState(0);
    const [rightEyeOffsetX, setRightEyeOffsetX] = useState(0);
    const [rightEyeOffsetY, setRightEyeOffsetY] = useState(0);
    const [eyeHeightOffset, setEyeHeightOffset] = useState(0);
    const [rightPupilShiftX, setRightPupilShiftX] = useState(0);
    const [rightPupilShiftY, setRightPupilShiftY] = useState(0);
    const [leftPupilShiftX, setLeftPupilShiftX] = useState(0);
    const [leftPupilShiftY, setLeftPupilShiftY] = useState(0);
    const [rightNoseCenterX, setRightNoseCenterX] = useState(0);
    const [rightNoseCenterY, setRightNoseCenterY] = useState(0);
    const [leftNoseCenterX, setLeftNoseCenterX] = useState(0);
    const [leftNoseCenterY, setLeftNoseCenterY] = useState(0);
    const [hairs, setHairs] = useState<any>([]);
    const [haventSleptForDays, setHaventSleptForDays] = useState(false);
    const [hairColor, setHairColor] = useState('black');
    const [dyeColorOffset, setDyeColorOffset] = useState("50%");
    const [mouthPoints, setMouthPoints] = useState<any>();
    const [randomBg, setRandomBg] = useState("")
    const uglyRef = createRef<SVGSVGElement>()
    const [src, setSrc] = useState(props.src)
    function generateFace() {
        setSrc("")
        setFaceScale(1.5 + Math.random() * 0.6);
        setHaventSleptForDays(Math.random() > 0.8)
        let faceResults = generateFaceCountourPoints();
        const faceWidth = faceResults.width;
        const faceHeight = faceResults.height;
        const ceenter = faceResults.center;
        const face = faceResults.face;
        setComputedFacePoints(face);
        setCenter(ceenter)

        let eyes = generateBothEyes(faceWidth / 2);
        let left = eyes.left;
        let right = eyes.right;

        setEyeRightUpper(right.upper);
        setEyeRightLower(right.lower);

        setEyeRightCountour(right.upper
            .slice(10, 90)
            .concat(right.lower.slice(10, 90).reverse()));
        setEyeLeftUpper(left.upper);
        setEyeLeftLower(left.lower);
        setEyeLeftCountour(left.upper
            .slice(10, 90)
            .concat(left.lower.slice(10, 90).reverse()));
        setDistanceBetweenEyes(randomFromInterval(
            faceWidth / 4.5,
            faceWidth / 4,
        ));
        setEyeHeightOffset(randomFromInterval(
            faceHeight / 8,
            faceHeight / 6,
        ));
        setLeftEyeOffsetX(randomFromInterval(
            -faceWidth / 20,
            faceWidth / 10,
        ));
        setLeftEyeOffsetY(randomFromInterval(
            -faceHeight / 50,
            faceHeight / 50,
        ));
        setRightEyeOffsetX(randomFromInterval(
            -faceWidth / 20,
            faceWidth / 10,
        ));
        setRightEyeOffsetY(randomFromInterval(
            -faceHeight / 50,
            faceHeight / 50,
        ));

        // now we generate the pupil shifts
        // we first pick a point from the upper eye lid
        let leftInd0 = Math.floor(randomFromInterval(10, left.upper.length - 10));
        let rightInd0 = Math.floor(
            randomFromInterval(10, right.upper.length - 10),
        );
        let leftInd1 = Math.floor(randomFromInterval(10, left.upper.length - 10));
        let rightInd1 = Math.floor(
            randomFromInterval(10, right.upper.length - 10),
        );
        let leftLerp = randomFromInterval(0.2, 0.8);
        let rightLerp = randomFromInterval(0.2, 0.8);
        setLeftPupilShiftY(left.upper[leftInd0][1] * leftLerp +
            left.lower[leftInd1][1] * (1 - leftLerp))
        setRightPupilShiftY(right.upper[rightInd0][1] * rightLerp +
            right.lower[rightInd1][1] * (1 - rightLerp))
        setLeftPupilShiftX(left.upper[leftInd0][0] * leftLerp +
            left.lower[leftInd1][0] * (1 - leftLerp));
        setRightPupilShiftX(right.upper[rightInd0][0] * rightLerp +
            right.lower[rightInd1][0] * (1 - rightLerp))

        var numHairLines = [];
        var numHairMethods = 4;
        for (var i = 0; i < numHairMethods; i++) {
            numHairLines.push(Math.floor(randomFromInterval(0, 50)));
        }

        if (Math.random() > 0.3) {
            let hairLine = generateHairLines0(
                face,
                numHairLines[0] * 1 + 10,
            );
            hairLine = hairLine.concat(
                generateHairLines1(
                    face,
                    numHairLines[1] / 1.5 + 10,
                ),
            )
            setHairs(hairLine);
        }
        if (Math.random() > 0.5) {

            let hairLine = hairs.concat(
                generateHairLines2(
                    face,
                    numHairLines[2] * 3 + 10,
                ),
            )
            hairLine = hairLine.concat(generateHairLines3(
                face,
                numHairLines[3] * 3 + 10,
            ))
            setHairs(hairLine);
        }
        setRightNoseCenterX(randomFromInterval(
            faceWidth / 18,
            faceWidth / 12
        ))
        setRightNoseCenterY(randomFromInterval(0, faceHeight / 5))
        setLeftNoseCenterX(randomFromInterval(
            -faceWidth / 18,
            -faceWidth / 12,
        ))
        setLeftNoseCenterY(randomFromInterval(0, faceHeight / 5) +
            randomFromInterval(-faceHeight / 30, faceHeight / 20))

        if (Math.random() > 0.1) {
            // use natural hair color
            setHairColor(hairColors[Math.floor(Math.random() * 10)])
        } else {
            setHairColor("url(#rainbowGradient)")
            setDyeColorOffset(randomFromInterval(0, 100) + "%");
        }

        var choice = Math.floor(Math.random() * 3);
        if (choice == 0) {
            setMouthPoints(generateMouthShape0(
                face,
                faceHeight,
                faceWidth,
            ))
        } else if (choice == 1) {
            setMouthPoints(generateMouthShape1(
                face,
                faceHeight,
                faceWidth,
            ))
        } else {
            setMouthPoints(generateMouthShape2(
                face,
                faceHeight,
                faceWidth,
            ))
        }
        setRandomBg(backgroundColors[Math.floor(Math.random() * backgroundColors.length)])
    }
    useEffect(() => { !src && generateFace() }, [])
    useImperativeHandle(ref, () => ({
        generateFace,
        dom: uglyRef.current
    }))
    return (
        <div id="ugly_avatar">
            {src ? <img style={{width:`${props.size || 40}px`,height:`${props.size || 40}px`}} src={src} /> : <svg
                viewBox="-100 -100 200 200"
                xmlns="http://www.w3.org/2000/svg"
                width={props.size || 40}
                height={props.size || 40}
                id="face-svg"
                ref={uglyRef}
            >
                <defs>
                    <clipPath id="leftEyeClipPath">
                        <polyline points={eyeLeftCountour} />
                    </clipPath>
                    <clipPath id="rightEyeClipPath">
                        <polyline points={eyeRightCountour} />
                    </clipPath>

                    <filter id="fuzzy">
                        <feTurbulence
                            id="turbulence"
                            baseFrequency="0.05"
                            numOctaves="3"
                            result="noise"
                        />
                        <feDisplacementMap in="SourceGraphic" in2="noise" scale="2" />
                    </filter>
                    <linearGradient id="rainbowGradient" x1="0%" y1="0%" x2="100%" y2="0%">
                        <stop
                            offset="0%"
                            style=
                            {{
                                stopColor:
                                    hairColors[Math.floor(Math.random() * 10)], stopOpacity: 1
                            }}
                        />
                        <stop
                            offset={dyeColorOffset}
                            style=
                            {{
                                stopColor:
                                    hairColors[Math.floor(Math.random() * hairColors.length)], stopOpacity: 1
                            }}

                        />
                        <stop
                            offset="100%"
                            style=
                            {{
                                stopColor:
                                    hairColors[Math.floor(Math.random() * hairColors.length)], stopOpacity: 1
                            }}
                        />
                    </linearGradient>
                </defs>
                <title>这是个丑头像</title>
                <desc>随机丑头像</desc>
                <rect
                    x="-100"
                    y="-100"
                    width="100%"
                    height="100%"
                    fill=
                    {randomBg}

                />
                <polyline
                    id="faceContour"
                    points={computedFacePoints}
                    fill="#ffc9a9"
                    stroke="black"
                    strokeWidth={3.0 / faceScale}
                    strokeLinejoin="round"
                    filter="url(#fuzzy)"
                />

                <g transform=
                    {'translate(' +
                        (center[0] + distanceBetweenEyes + rightEyeOffsetX) +
                        ' ' +
                        -(-center[1] + eyeHeightOffset + rightEyeOffsetY) +
                        ')'}
                >
                    <polyline
                        id="rightCountour"
                        points={eyeRightCountour}
                        fill="white"
                        stroke="white"
                        strokeWidth={0.0 / faceScale}
                        strokeLinejoin="round"
                        filter="url(#fuzzy)"
                    />
                </g>
                <g
                    transform=
                    {'translate(' +
                        -(center[0] + distanceBetweenEyes + leftEyeOffsetX) +
                        ' ' +
                        -(-center[1] + eyeHeightOffset + leftEyeOffsetY) +
                        ')'}

                >
                    <polyline
                        id="leftCountour"
                        points={eyeLeftCountour}
                        fill="white"
                        stroke="white"
                        strokeWidth={0.0 / faceScale}
                        strokeLinejoin="round"
                        filter="url(#fuzzy)"
                    />
                </g>
                <g
                    transform=
                    {'translate(' +
                        (center[0] + distanceBetweenEyes + rightEyeOffsetX) +
                        ' ' +
                        -(-center[1] + eyeHeightOffset + rightEyeOffsetY) +
                        ')'}

                >
                    <polyline
                        id="rightUpper"
                        points={eyeRightUpper}
                        fill="none"
                        stroke="black"
                        strokeWidth={(haventSleptForDays ? 5.0 : 3.0) / faceScale}
                        strokeLinejoin="round"
                        strokeLinecap="round"
                        filter="url(#fuzzy)"
                    />
                    <polyline
                        id="rightLower"
                        points={eyeRightLower}
                        fill="none"
                        stroke="black"
                        strokeWidth={(haventSleptForDays ? 5.0 : 3.0) / faceScale}
                        strokeLinejoin="round"
                        strokeLinecap="round"
                        filter="url(#fuzzy)"
                    />
                    {Array.from({ length: 10 }, (_, index) => index).map(i => <circle
                        key={i}
                        r={Math.random() * 2 + 3.0}
                        cx={rightPupilShiftX + Math.random() * 5 - 2.5}
                        cy={rightPupilShiftY + Math.random() * 5 - 2.5}
                        stroke="black"
                        fill="none"
                        strokeWidth={1.0 + Math.random() * 0.5}
                        filter="url(#fuzzy)"
                        clipPath="url(#rightEyeClipPath)"
                    />)}

                </g >
                <g transform=
                    {'translate(' +
                        -(center[0] + distanceBetweenEyes + leftEyeOffsetX) +
                        ' ' +
                        -(-center[1] + eyeHeightOffset + leftEyeOffsetY) +
                        ')'}

                >
                    <polyline
                        id="leftUpper"
                        points={eyeLeftUpper}
                        fill="none"
                        stroke="black"
                        strokeWidth={(haventSleptForDays ? 5.0 : 3.0) / faceScale}
                        strokeLinejoin="round"
                        filter="url(#fuzzy)"
                    />
                    <polyline
                        id="leftLower"
                        points={eyeLeftLower}
                        fill="none"
                        stroke="black"
                        strokeWidth={(haventSleptForDays ? 5.0 : 3.0) / faceScale}
                        strokeLinejoin="round"
                        filter="url(#fuzzy)"
                    />
                    {Array.from({ length: 10 }, (_, index) => index).map(i => <circle
                        key={i}
                        r={Math.random() * 2 + 3.0}
                        cx={leftPupilShiftX + Math.random() * 5 - 2.5}
                        cy={leftPupilShiftY + Math.random() * 5 - 2.5}
                        stroke="black"
                        fill="none"
                        strokeWidth={1.0 + Math.random() * 0.5}
                        filter="url(#fuzzy)"
                        clipPath="url(#rightEyeClipPath)"
                    />)}
                </g >
                <g id="hairs">
                    {hairs.map((hair: string, index: number) => <polyline
                        key={index}
                        points={hair}
                        fill="none"
                        stroke={hairColor}
                        strokeWidth={0.5 + Math.random() * 2.5}
                        strokeLinejoin="round"
                        filter="url(#fuzzy)"
                    />)}

                </g>
                {Math.random() > 0.5 ? <g id="pointNose" >
                    <g id="rightNose">
                        {Array.from({ length: 10 }, (_, i) => i).map(i => <circle
                            v-for="i in 10"
                            key={i}
                            r={Math.random() * 2 + 1.0}
                            cx={rightNoseCenterX + Math.random() * 4 - 2}
                            cy={rightNoseCenterY + Math.random() * 4 - 2}
                            stroke="black"
                            fill="none"
                            strokeWidth={1.0 + Math.random() * 0.5}
                            filter="url(#fuzzy)"
                        />)}

                    </g>
                    <g id="leftNose">
                        {Array.from({ length: 10 }, (_, i) => i).map(i => <circle
                            v-for="i in 10"
                            key={i}
                            r={Math.random() * 2 + 1.0}
                            cx={rightNoseCenterX + Math.random() * 4 - 2}
                            cy={rightNoseCenterY + Math.random() * 4 - 2}
                            stroke="black"
                            fill="none"
                            strokeWidth={1.0 + Math.random() * 0.5}
                            filter="url(#fuzzy)"
                        />)}
                    </g>
                </g> : <g id="lineNose">
                    <path d=
                        {'M ' + leftNoseCenterX + ' ' + leftNoseCenterY + ', Q' + rightNoseCenterX + ' ' + rightNoseCenterY * 1.5 + ',' + (leftNoseCenterX + rightNoseCenterX) / 2 + ' ' + -eyeHeightOffset * 0.2}
                        fill="none"
                        stroke="black"
                        strokeWidth={2.5 + Math.random() * 1.0}
                        strokeLinejoin="round"
                        filter="url(#fuzzy)"
                    ></path>
                </g >}


                <g id="mouth">
                    <polyline points={mouthPoints}
                        fill="rgb(215,127,140)"
                        stroke="black"
                        strokeWidth={2.7 + Math.random() * 0.5}
                        strokeLinejoin="round"
                        filter="url(#fuzzy)"
                    />
                </g>
            </svg>}

            {/* <Button onClick={generateFace}>Next</Button> */}
        </div >
    );
})

export default UglyAvatar;
